package virtualinit;

import virtualinit.util.JdbcUtil;
import virtualinit.util.Log;

import java.io.Serializable;
import java.sql.Connection;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

public abstract class AbstractInit {
    Config config = Config.instance;
    static Log log = Log.instance;


    public static Map<String, AtomicLong> tbCounts = new HashMap<>();

    public static long totalTarget = 0;
    public static long totalSourceSize = 0;
    public boolean finished;
    public String storageDbName;
    public String scheduleDbName;
    public Ds scheduleDS;
    public Ds storageDS;
    protected Connection storageConn;
    protected Connection scheduleConn;

    InsertTask task = new InsertTask();

    public static Map<String, Map<String, Object>> storeIdToRoute;

    String insertSqlPrefix = "INSERT INTO {} (tenant_id,app_id,created_time,updated_time,virtual_depot_id,channel_id,store_id,sku_id,sku_type,feature)values";
    String fields = "(tenant_id,app_id,created_time,updated_time,virtual_depot_id,channel_id,store_id,sku_id,sku_type,feature)values";

    String onDuplicate = " ON DUPLICATE KEY update updated_time=now(),version=version+1";


    public static StringBuilder values(boolean withSplit, Object... arr) {
        StringBuilder sb = new StringBuilder(200);
        if (withSplit) {
            sb.append(',');
        }
        sb.append('(');
        for (int i = 0; i < arr.length; i++) {
            Object o = arr[i];
            if (i != 0) {
                sb.append(',');
            }
            if (o instanceof String) {
                sb.append("'").append(o).append("'");
            } else {
                sb.append(o);
            }
        }
        sb.append(')');
        return sb;
    }

    protected Serializable getTableRoute(String storeId) {
        Map<String, Object> route = storeIdToRoute.get(storeId);
        if (route == null) {
            log.error("storeId={} 没有路由信息", storeId);
            return null;
        }
        return (Serializable) route.get("table_name");
    }

    Map<String, String> existMap;

    // 记录重复
    protected void recordRepeat(Object... values) {
        if (existMap == null)
            existMap = new HashMap<>(1024 * 1024);
        String k = Arrays.toString(values);
        if (existMap.containsKey(k)) {
            System.out.println("发现重复：" + k);
        } else {
            existMap.put(k, null);
        }
    }

    public void start() throws Exception {
        doStart();
    }

    public abstract void doStart() throws Exception;

    public void finish() {
        scheduleDS.returnConnection(scheduleConn);
        storageDS.returnConnection(storageConn);
    }

    protected void addSql(SqlHolder sqlHolder) {
        task.addSql(sqlHolder);
    }

    boolean init = false;
    protected void init() {
        if(!init)init=true;
        config.initVirtualStockConfig();
        config.nameToDs.values().forEach(e -> e.init(config.threadPoolSize + 1));

        this.scheduleDS = config.domainToDs.get(config.scheduleDomainKey);
        this.storageDS = config.domainToDs.get(config.storageDomainKey);
        storageConn = storageDS.takeConnection();
        scheduleConn = scheduleDS.takeConnection();
        this.storageDbName = config.domainDbNameMapping.get(config.storageDomainKey);
        this.scheduleDbName = config.domainDbNameMapping.get(config.scheduleDomainKey);

        if (storeIdToRoute == null) {
            List<Map<String, Object>> depotRoute = JdbcUtil.executeToMap(storageConn,
                    "select id,depot_id,store_id,table_name,depot_type from ?.st_depot_route where is_deleted=0"
                            .replace("?", JdbcUtil.quoteIdentifier(storageDbName)));
            log.info("初始化depot route, 大小:" + depotRoute.size());
            storeIdToRoute = depotRoute.stream().collect(Collectors.toMap(e -> e.get("store_id").toString(), e -> e));
        }

    }

    protected SqlHolder getSqlHolder(Map<String, SqlHolder> sqlCache, String channelId, String storeId) {
        if (config.channelForbidden(channelId)) return null;
        channelId = channelId.toLowerCase();
        Ds ds = config.channelToDs.get(channelId);
        String db = config.initVirtualStockConfig.subDatabasePrefix + channelId;
        if (ds == null) {
            ds = config.initVirtualStockConfig.defaultChannelDs;
            // 默认db
            db = config.initVirtualStockConfig.defaultChannelDbName;
            channelId = "default";
        }

        if (getTableRoute(storeId) == null) {
            return null;
        }

        AtomicLong count = tbCounts.get(db);
        if (count == null)
            tbCounts.put(db, count = new AtomicLong());
        count.incrementAndGet();

        String table = '`' + db + "`." + config.initVirtualStockConfig.subTablePrefix + getTableRoute(storeId);
        SqlHolder sqlHolder = sqlCache.get(table);
        if (sqlHolder == null) {
            sqlCache.put(table, sqlHolder = new SqlHolder());
            sqlHolder.sql.append("insert into ").append(table).append(fields);
            sqlHolder.initLen = sqlHolder.sql.length();
            sqlHolder.table = table;
            sqlHolder.ds = ds;
        }
        return sqlHolder;
    }

    public abstract String getTaskName();
}
